package com.huwei.modules.base.util;


import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * 文件工具
 * @author huwei
 * @version 1.0
 */
public class FileUtil {
	
//	public static void main(String[] args) throws IOException {
//		byte[] res = read("classpath:resources/a.name", "test");
//		System.out.println("---> :" + new String(res));
//		byte[] res2 = read("classpath:config/application.properties", "test");
//		System.out.println("---> :" + new String(res2));
//		byte[] res3 = read("classpath:config/a.mapper", "test");
//		System.out.println("---> :" + new String(res3));
//	}
	
	/**
	 * 读取指定的路径文件，该方法将以：绝对路径 -> 普通java应用 -> web应用 的顺序解析文件路径，并获取文件数据，
	 * 失败抛出异常；
	 * 注意jarName需要与打包后的jarName一致；
	 * 示例：
	 * try{
	 * 	byte[] res = FileUtil.read("classpath:resources/a.name" ,"jarName");
	 * } catch(IOException e){
	 * }
	 * 示例说明：
	 * classpath路径说明：
	 * 1，普通java应用中：如果当前根目录中包含target/classes/，则表示项目根目录与target/classes/组合后的目录下，对应项目
	 * 文件中的：src/mian/java 与 src/main/resources目录下的所有文件； 反之，如果不存在target/classes ，即手动编译
	 * 的项目，则从根目录开始；
	 * 2，web应用中： classpath表示src/mian/java 与 src/main/resources目录下的所有文件,而这些文件保存在root与
	 * WEB-INF/classes组合后的目录下；
	 * @param pathName 路径文件
	 * @param jarName 打包后的jar名称
	 * @return
	 * @throws IOException
	 */
	static public byte[] read(String pathName) throws IOException {
		if (pathName == null || pathName.trim().equals("")) {
			throw new IOException("指定文件路径为空，请检测参数pathName：" + pathName);
		}
		pathName = switchPathSymbol(pathName);
		// 绝对路径
		File file = new File(pathName);
		try {
			return readAll(file);
		} catch (IOException e) {
			// TODO: handle exception
		}
		// 相对路径
		// 项目根目录
		String root = Thread.currentThread().getContextClassLoader().getResource("").getFile();
		// 当前项目为普通java应用程序
		// path路径中包含classpath指定，将classpath替换为/target/classes/目录
		String newPath = pathName.startsWith("classpath")
				? detectAndGetPathName(root, "target/classes/") + pathName.substring(pathName.indexOf(":") + 1)
				: pathName;
		//源路径
		file = new File(root + "/" + newPath);
		try {
			return readAll(file);
		} catch (IOException e) {
			// TODO: handle exception
		}
		
		//移除路径中的resources/路径
		newPath = newPath.replace("resources/", "");
		file = new File(root + "/" + newPath);
		try {
			return readAll(file);
		} catch (IOException e) {
			// TODO: handle exception
		}
		
		//不是以web 方式运行
		if(root.indexOf("WEB-INF") == -1) {
			throw new IOException("未找到指定文件，请检测参数pathName:" + pathName);
		}

		// 当前项目以运行在web容器中
		String webRoot = root.substring(0, root.indexOf("WEB-INF"));
		// path路径中包含classpath指定，将classpath替换为/WEB-INF/classes/目录
		String webPath = pathName.startsWith("classpath") 
				? "WEB-INF/classes/" + pathName.substring(pathName.indexOf(":") + 1)
				: pathName;
		//源路径
		file = new File(webRoot + "/" + webPath);
		try {
			return readAll(file);
		} catch (IOException e) {
			// TODO: handle exception
		}
		//移除resources/路径
		String webPath2 = webPath.replace("resources/", "");
		file = new File(webRoot + "/" + webPath2);
		try {
			return readAll(file);
		} catch (IOException e) {
			// TODO: handle exception
		}
		//path路径中包含src/main/webapp/指定，将截取src/main/webapp/之后的路径
		String webPath3 = pathName.startsWith("src/main/webapp/")
				? detectAndGetPathName(root, "src/main/webapp/") + pathName.substring(pathName.indexOf("src/main/webapp/") + "src/main/webapp/".length())
				: pathName;
		file = new File(webRoot + "/" + webPath3);
		return readAll(file);
	}
	
	/**
	 * 读取指定的路径文件，该方法将以：绝对路径 -> 普通java应用 -> web应用 -> jar文件 的顺序解析文件路径，并获取文件数据，
	 * 失败抛出异常；
	 * 注意jarName需要与打包后的jarName一致；
	 * 示例：
	 * try{
	 * 	byte[] res = FileUtil.read("classpath:resources/a.name" ,"jarName");
	 * } catch(IOException e){
	 * }
	 * 示例说明：
	 * classpath路径说明：
	 * 1，普通java应用中：如果当前根目录中包含target/classes/，则表示项目根目录与target/classes/组合后的目录下，对应项目
	 * 文件中的：src/mian/java 与 src/main/resources目录下的所有文件； 反之，如果不存在target/classes ，即手动编译
	 * 的项目，则从根目录开始；
	 * 2，web应用中： classpath表示src/mian/java 与 src/main/resources目录下的所有文件,而这些文件保存在root与
	 * WEB-INF/classes组合后的目录下；
	 * 3，jar应用中：classpath表示src/mian/java 与 src/main/resources目录下的所有文件，但resources目录下的资源
	 * 将被包含在resources目录文件下，而classpath对应jar文件解压后的第一层级；
	 * @param pathName 路径文件
	 * @param jarName 打包后的jar名称
	 * @return
	 * @throws IOException
	 */
	@SuppressWarnings("resource")
	static public byte[] read(String pathName, String jarName) throws IOException {
		try {
			return read(pathName);
		} catch (IOException e) {
		}
		if(jarName == null || "".equals(jarName)) {
			throw new IOException("参数jarName为空，jarName ：" + jarName);
		}
		
		byte[] res = null;
		// 项目根目录
		String root = Thread.currentThread().getContextClassLoader().getResource("").getFile();
		root = root.startsWith("file:") ? root.substring(5) : root;
		// 当前项目已jar包的方式运行；
		// path路径中包含classpath指定，截取指定后面的路径
		String newPath = pathName.startsWith("classpath") ? pathName.substring(pathName.indexOf(":") + 1) : pathName;
		
		JarFile jarFile = null;
		String jarPath = root.indexOf(".jar") != -1 
				? root.substring(0, root.indexOf(".jar") + 4)
				: root + "/" + (jarName.endsWith(".jar") ? jarName : jarName + ".jar");
		try {
			jarFile = new JarFile(jarPath);
		} catch (IOException e) {
			throw new IOException("未找到指定运行的jar文件,请查找jar文件：" + jarPath );
		}
		//查找resources目录中的文件
		String inResourcesPath = "resources/" + newPath;
		//mvn自动打包
		String mvnPath = "BOOT-INF/classes/" + (newPath.startsWith("resources/") ? newPath.replace("resources/", "") : newPath);
		Enumeration<JarEntry> enu = jarFile.entries();
		while (enu.hasMoreElements()) {
			JarEntry entry = enu.nextElement();
			String name = entry.getName();
			if (name.equals(newPath)) {
				return readAll(jarFile.getInputStream(entry));
			} else if (name.equals(inResourcesPath)) {
				res = readAll(jarFile.getInputStream(entry));
			} else if(name.equals(mvnPath)) {
				res = readAll(jarFile.getInputStream(entry));
			}
		}
		if(res != null) {
			return res;
		}
		throw new IOException("未找到资源文件");
	}

	/**
	 * 从给定file中读取数据，失败抛出IO异常，反之，结果非空
	 * @param file 读取文件
	 * @return 失败抛出IO异常，反之，结果非空
	 * @throws IOException
	 */
	static public byte[] readAll(File file) throws IOException {
		if (file == null || !file.exists() || file.isDirectory()) {
			throw new IOException("文件为空或指定文件不存在 ，请检测参数file ：" + file);
		}
		return readAll(new FileInputStream(file));
	}
	
	static private byte[] readAll(InputStream is) throws IOException {
		byte[] res = new byte[is.available()];
		is.read(res);
		is.close();
		return res;
	}

	/**
	 * 替换指定文件路径的文件分割符号
	 */
	static private String switchPathSymbol(String pathName) {
		return pathName.replace("\\\\", "/");
	}
	
	/**
	 * 从给定root路径下查找target文件或目录是否存储
	 * @param root root路径，该路径为绝对路径
	 * @param target 目标文件或目录
	 * @return 存在返回target表示字符，反之，返回空串
	 */
	static private String detectAndGetPathName(String root ,String target) {
		return detectAndGetPathName(root, target, "");
	}
	/**
	 * 从给定root路径下查找target文件或目录是否存储
	 * @param root root路径，该路径为绝对路径
	 * @param target 目标文件或目录
	 * @param defaultValue 自定义默认返回值
	 * @return 存在返回target表示字符，反之，返回空串
	 */
	static private String detectAndGetPathName(String root ,String target ,String defaultValue) {
		File file = new File(root + "/" + target);
		if(file.exists()) {
			return target;
		}
		return defaultValue;
	}
}
